/*
 * ResourceAnalysisUnit.cpp
 *
 *  Created on: Nov 17, 2008
 *      Author: Ryan
 */

#include "ResourceAnalysisUnit.h"

#include "../../OOInterface/Objects/Logger.h"

#include <cmath>

ResourceAnalysisUnit::ResourceAnalysisUnit( OOInterface::AIInterface* i , const OOInterface::Resource r, const OOInterface::Point3f loc, float searchRadius, ResourceNodes prevExtractors, float extractorRadius ):
	_isDone(false), _i( i ), _resource( r ), _loc( loc ),
	_searchRadius( searchRadius ), _oldExtractors( prevExtractors ), _extractorRadius( extractorRadius )
{
}

ResourceAnalysisUnit::~ResourceAnalysisUnit()
{
}

void ResourceAnalysisUnit::run()
{
	const OOInterface::GameMap& map = _i->getGameMap();
	int height = map.getHeight();
	int width = map.getWidth();
	float* valueAtLoc = new float[ width * height ];;
	float* resourceMap = new float[ width * height ];;

	initializeMaps( valueAtLoc, resourceMap );

	calculateValueLoc( resourceMap, valueAtLoc );

	int x = 0;
	int y = 0;

	findMaxNode( valueAtLoc, x, y, width, height );

	_points.push( OOInterface::Point3f(x, 0.0f, y ));

	_isDone = true;
	delete[] valueAtLoc;
	delete[] resourceMap;
}

void ResourceAnalysisUnit::initializeMaps( float* valueMap, float* resourceMap )
{
	const OOInterface::GameMap& map = _i->getGameMap();
	int height = map.getHeight();
	int width = map.getWidth();

	int centerX = _loc.getX();
	int centerY = _loc.getZ();


	int valueRadius = _extractorRadius + _searchRadius;

	int* xEnd = new int[ int(valueRadius * 2) + 1];
	for( int a = 0; a < valueRadius * 2; ++a )
		xEnd[a] = int( sqrt( valueRadius*valueRadius - (a-valueRadius)*(a-valueRadius) ) );


	for ( int sy = centerY - valueRadius, a = 0; sy < centerY + valueRadius; ++sy, ++a )
	{
		if( sy < 0 || sy >= height || a >= valueRadius * 2)
			continue;

		for( int sx = centerX - xEnd[a]; sx <= centerX + xEnd[a]; ++sx )
		{
			if( sx < 0 || sx >= width )
				continue;

			resourceMap[sy * width + sx ] = map.getResourceDensity( _resource, sx, sy );
			valueMap[ sy * width + sx ] = 0.0f;
		}

	}

	while( !_oldExtractors.empty() )
	{
		updateResourceMap( resourceMap, width, height, _oldExtractors.front(), _extractorRadius );
		_oldExtractors.pop();
	}

	delete[] xEnd;
}

void ResourceAnalysisUnit::updateResourceMap( float* map, int width, int height, OOInterface::Point3f& p, float radius )
{
	//OOInterface::Logger::getInstance("AI.txt") << "Updating Resource Map" << std::endl;
	int* xEnd = new int[ int(radius * 2.0f) + 1];

	for( int a = 0; a < radius * 2; ++a )
		xEnd[a] = int( sqrt( radius*radius - (a-radius)*(a-radius) ) );


	int x = p.getX();
	int y = p.getZ();

	for ( int sy = y - radius, a =0; sy < y + radius; ++sy, ++a )
	{
		if( sy < 0 || sy >= height || a >= radius * 2)
			continue;

		for( int sx = x - xEnd[a]; sx <= x + xEnd[a]; ++sx )
		{
			if( sx < 0 || sx >= width )
				continue;

			map[sy * width + sx ] = 0.0f;
		}

	}

	delete[] xEnd;

}

void ResourceAnalysisUnit::calculateValueLoc( float* map, float* valueLoc )
{
	//OOInterface::Logger::getInstance("AI.txt") << "Calculating Map values" << std::endl;
	const OOInterface::GameMap& gameMap = _i->getGameMap();
	int height = gameMap.getHeight();
	int width = gameMap.getWidth();

	int centerX = _loc.getX();
	int centerY = _loc.getZ();

	int* xEnd = new int[ int(_searchRadius * 2) + 1];
	for( int a = 0; a < _searchRadius * 2; ++a )
		xEnd[a] = int( sqrt( _searchRadius*_searchRadius - (a-_searchRadius)*(a-_searchRadius) ) );


	for ( int sy = centerY - _searchRadius, a = 0; sy < centerY + _searchRadius; ++sy, ++a )
	{
		if( sy < 0 || sy >= height || a >= _searchRadius * 2)
			continue;

		for( int sx = centerX - xEnd[a]; sx <= centerX + xEnd[a]; ++sx )
		{
			if( sx < 0 || sx >= width )
				continue;

			calculateValueLocAt( map, valueLoc, sx, sy);
		}

	}

	delete[] xEnd;
}

void ResourceAnalysisUnit::calculateValueLocAt( float* map, float* valueLoc, int x, int y )
{
	const OOInterface::GameMap& gameMap = _i->getGameMap();
	int height = gameMap.getHeight();
	int width = gameMap.getWidth();

	int* xEnd = new int[ int(_extractorRadius * 2) + 1];
	for( int a = 0; a < _extractorRadius * 2; ++a )
		xEnd[a] = int( sqrt( _extractorRadius*_extractorRadius - (a-_extractorRadius)*(a-_extractorRadius) ) );

	float value = 0.0f;

	for ( int sy = y - _extractorRadius, a = 0; sy < y + _extractorRadius; ++sy, ++a )
	{
		if( sy < 0 || sy >= height || a >= _extractorRadius * 2)
			continue;

		for( int sx = x - xEnd[a]; sx <= x + xEnd[a]; ++sx )
		{
			if( sx < 0 || sx >= width )
				continue;

			value += map[ sy * width + sx ];
		}

	}

	if( y * width + x < width * height)
		valueLoc[ y * width + x ] = value;

	delete[] xEnd;
}

float ResourceAnalysisUnit::findMaxNode( float* valueLoc, int& x, int& y, int width, int height )
{
	//OOInterface::Logger::getInstance("AI.txt") << "Finding max node." << std::endl;
	float currMax = 0.0f;

	for( int sx = 0; sx < width; ++sx )
		for( int sy = 0; sy < height; ++sy )
			if( valueLoc[ sy* width + sx ] > currMax )
			{
				x = sx; y = sy;
				currMax = valueLoc[ sy * width + sx ];
			}

	return currMax;
}

